<?php

namespace app\admin\controller;

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
header('Access-Control-Allow-Methods: GET, POST, PUT,DELETE');
header("Content-type: text/html; charset=utf-8");
use app\models\AuthGroupAccessModel;
use app\models\AuthModel;
use app\models\DictionaryModel;
use app\models\MenuModel;
use think\Cache;
use think\Controller;
use think\Request;
use think\Config;

class Common extends Controller
{
    /**
     * 非法请求
     */
    const REQUEST_METHOD_ERROR = 4000001;
    /**
     * 签名错误.
     */
    const SIGN_ERROR = 4000002;
    /**
     * 接口签名key.
     *
     * @var string
     */
    protected $signKey;
    /**
     * 返回状态码
     *
     * @var string
     */
    protected $code = 0;
    /**
     * 返回状态信息.
     *
     * @var string
     */
    protected $message = 'fail';
    /**
     * 返回数据(包含code和message).
     *
     * @var array
     */
    protected $returnData = [];
    /**
     * 错误码与错误信息映射.
     *
     * @var array
     */
    protected $mapErrorMsg = [
        self::REQUEST_METHOD_ERROR => '非法请求',
        self::SIGN_ERROR => '签名错误',
    ];

    protected $msg;

    /**
     * cookie 缓存过期时间.
     *
     * @var mixed
     */
    protected $cookieExpireTime;

    /**
     * 缓存前缀.
     *
     * @var string
     */
    protected $courseContractModel;

    /**
     * 缓存标签后缀.
     *
     * @var string
     */
    protected $companyModel;

    /**
     * DictionaryModel 字典模型.
     *
     * @var DictionaryModel
     */
    protected $dictionaryModel;
    /**
     * BackendController constructor.
     *
     * @param Request $request
     */
    public function __construct(Request $request)
    {
        parent::__construct($request);
        // 控制器初始化
        $this->_initialize();
        // cookie 过期时间
        $this->cookieExpireTime = Config::get('cookie_expire_time');
    }

    protected function _initialize()
    {
        $this->dictionaryModel = new DictionaryModel();
        $this->signKey = config('sign_key');
        if (!$this->isLogin()) {
            if (request()->isPost()) {
                return ['code' => 1, 'msg' => '当前处于退出登录状态'];
            }
            $this->redirect('Account/login');
        }
        $controller = $this->request->controller();
        $action = $this->request->action();
        $code = $controller.'/'.$action;
        $user = session('user');
        $group_id = AuthGroupAccessModel::where('uid', $user['id'])->value('group_id');
        $group = explode(',', $group_id);
        foreach ($group as $v) {
            if (in_array((int) $v, config('administrator'), true)) {
                $this->assign('administrator', 1);

                return true;
            }
        }
        $this->assign('administrator', 0);
        $rules = AuthModel::where('id', 'IN',$group_id)->field('rules')->select()->toArray();
        //将权限规则拼成字符串
        $rules = implode(',',array_column($rules,'rules'));
        //将权限规则转成数组再去重，再转成字符串，由数据结构阶决定的
        $rules = implode(',',array_unique(explode(',',$rules)));
        $menuName = MenuModel::where('id', 'IN', $rules)->field('menu_name')->select()->toArray();
        $menuName = array_column($menuName,'menu_name');
        if (!in_array($controller, config('not_auth_controller'), true) && !in_array($code, $menuName, true)) {
            $this->assign('jsClose', 1);
            $this->error('您没有权限进行此操作');
        }
    }

    /**
     * 参数加签.
     *
     * @param $data array 接口参数
     *
     * @return string
     */
    public function decodeSign($data)
    {
        $data = array_change_key_case($data);
        ksort($data);
        foreach ($data as &$val) {
            if (is_array($val)) {
                $val = json_encode($val, JSON_UNESCAPED_UNICODE);
            }
        }
        $data = $this->_buildQuery($data);

        return  strtoupper(md5($data.'&key='.$this->signKey));
    }

    /**
     * 校验签名.
     *
     * @param $data
     * @param $sign
     *
     * @return bool
     */
    public function verifySign($data)
    {
        $sign = isset($data['sign']) ? $data['sign'] : false;
        if ($sign) {
            unset($data['sign']);
        }
        //缓存签名sign 防止重复使用
        if ($sign === $this->decodeSign($data) && !Cache::has('v3i_sign_'.$sign)) {
            Cache::set('v3i_sign_'.$sign, json_encode($data), 600);

            return true;
        }

        return false;
    }

    /**
     * 检查请求方式是否为POST（默认要求为：POST）.
     *
     * @return bool
     */
    public function isRequestMethod()
    {
        return Request::instance()->isPost() ? true : false;
    }

    /**
     * 前置检查.
     *
     * @param $data
     *
     * @return bool|string
     */
    public function beforeCheck($data)
    {
        if (!$this->isRequestMethod()) {
            return $this->mapErrorMsg[self::REQUEST_METHOD_ERROR];
        }
        if (!$this->verifySign($data)) {
            return $this->mapErrorMsg[self::SIGN_ERROR];
        }

        return true;
    }

    /**
     * 拼装签名前的字符串.
     *
     * @param $data
     *
     * @return string
     */
    public function _buildQuery($data)
    {
        $str = '';
        if (is_array($data)) {
            foreach ($data as $key => $value) {
                if (is_array($value)) {
                    $str .= $key.'='.json_encode($value).'&';
                } else {
                    $str .= $key.'='.$value.'&';
                }
            }
            $str = mb_substr($str, 0, -1);
        } else {
            $str = $data;
        }

        return $str;
    }

    /**
     * 判断当前用户是否登录.
     *
     * @return bool
     */
    private function isLogin()
    {
        $user = session('user');
        return $user ? true : false;
    }

    /**
     * 字典
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function dictionary()
    {
        $dictionarys = $this->dictionaryModel->where(['status'=>1])->select()->toArray();
        $_type = array_column($dictionarys,'type');
        $data = [];
        foreach ($dictionarys as $dictionary) {
            foreach ($_type as $v) {
                if($v === $dictionary['type']){
                    $data[$v][] = $dictionary;
                    break;
                }
            }
        }
        $this->assign('data',$data);
    }
}
